#ifndef _TCP_SERVER_HPP
#define _TCP_SERVER_HPP

#include <iostream>
#include <string>
#include <cstring>
#include <memory>
#include <assert.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include "./threadPool/log.hpp"
#include "./threadPool/threadpool.hpp"
#include "./threadPool/Task.hpp"

#define SIZE 1024

//////////////////////////////////////////////////////////
// 业务函数：服务器用于处理业务，可根据需求自定义


// 【version4：echo版服务器】：和上面的相同，只是为了显示是哪个新线程执行的业务处理，新增了参数
static void service(int servicesock, const std::string &clientip, const uint16_t &clientport, const std::string &threadname)
{
    char server_buffer[SIZE];
    while (true)
    {
        // a、读取客户端发来的数据
        ssize_t s = read(servicesock, server_buffer, sizeof(server_buffer) - 1);
        if (s > 0)
        {
            server_buffer[s] = '\0'; //\0的ASCII码是0
            std::cout << threadname << "| " << clientip << ":" << clientport << "# " << server_buffer << std::endl;
        }
        else if (s == 0)
        {
            logMessage(NORMAL, "read, %s:%d 退出。", clientip.c_str(), clientport);
            break;
        }
        else
        {
            logMessage(ERROR, "read, 读取失败, %d:%s", errno, strerror(errno));
            break;
        }

        // b、将读取到的结果返回
        write(servicesock, server_buffer, strlen(server_buffer));
    }
     close(servicesock);
}


class TcpServer
{
private:
    const static int gbacklog = 20; // listen中的参数设置

public:
    TcpServer(uint16_t port, const std::string &ip = "") //在构造时，初始化其它变量时也要初始化线程库
        : _port(port), _ip(ip), _listensock(-1),_pthreadpool(ThreadPool<Task>::getThreadPool())
    {
    }

    ~TcpServer()
    {
        close(_listensock);
    }

    // 初始化服务器
    bool InitServer()
    {
        // 1、创建套接字
        _listensock = socket(AF_INET, SOCK_STREAM, 0); // 这里填入SOCK_STREAM
        if (_listensock < 0)
        {
            logMessage(ERROR, "socket, 创建套接字失败: %s-%d ", errno, strerror(errno));
            exit(2);
        }
        logMessage(DEBUG, "socket, 创建套接字成功,sock: %d", _listensock);

        // 2、绑定
        struct sockaddr_in localaddr;
        bzero(&localaddr, 0);
        localaddr.sin_family = AF_INET;
        localaddr.sin_addr.s_addr = _ip.empty() ? INADDR_ANY : inet_addr(_ip.c_str()); // 字节序转换
        localaddr.sin_port = htons(_port);
        if (bind(_listensock, (struct sockaddr *)&localaddr, sizeof localaddr) < 0)
        {
            logMessage(ERROR, "bind, 绑定失败，%d:%s", errno, strerror(errno));
            exit(3);
        }
        logMessage(DEBUG, "bind, 绑定成功. ");

        // 3、监听
        if (listen(_listensock, gbacklog) < 0)
        {
            logMessage(ERROR, "listen, 监听失败，%d:%s", errno, strerror(errno));
            exit(4);
        }
        logMessage(DEBUG, "linsten, 监听成功, 初始化套接字完成。");

        return true;
    }

    // 启动服务器
    void Start()
    {
        _pthreadpool->run();//【version4】:在启动服务器时，一并将线程池中的线程启动（创建）

        // 网络通讯角度：作为一款网络服务器，永远不退出的！
        // OS角度：服务器启动-> 进程 -> 常驻进程 -> 永远在内存中存在，除非挂了！
        while (true)
        {
            // 1、获取连接
            // 1.1、准备工作：用于后续从网络中读取客户端的IP、端口号
            struct sockaddr_in clientaddr;
            memset(&clientaddr, 0, sizeof(clientaddr));
            socklen_t len = sizeof(clientaddr);
            // 1.2、连接
            int servicesock = accept(_listensock, (struct sockaddr *)&clientaddr, &len);
            if (servicesock < 0)
            {
                logMessage(ERROR, "accept, 获取链接失败, servicesock: %d ", servicesock);
                continue; // 本次失败了，结束此次循环即可，可下一次重新获取连接
            }

            // 2、开始进行通讯服务
            // 2.1、获取客户端端口号、IP
            uint16_t client_port = ntohs(clientaddr.sin_port);      // uint16_t htons(uint16_t hostshort);
            std::string client_ip = inet_ntoa(clientaddr.sin_addr); // char *inet_ntoa(struct in_addr in);
            logMessage(DEBUG, "accept, 成功获取连接,  servicesock: %d, client: [%s:%d] .", servicesock, client_ip.c_str(), client_port);

            ////////////////////////////////////////////////////////////////////////////
            // 2.2、根据需求处理客户端数据（服务端的业务处理）

            // ——————————【version4:线程池版本】———————————//
            // a、主线程派发任务对象：将客服端当作一个任务对象，创建后放入线程池中，后续由线程池中的新线程来执行。
            Task t(servicesock, client_ip, client_port, service);
            _pthreadpool->pushTask(t);
            // ———————————————————————————————————————————//
           
        }
    }

private:
    uint16_t _port;                                 // 端口号
    std::string _ip;                                // IP
    int _listensock;                                // 套接字
    std::unique_ptr<ThreadPool<Task>> _pthreadpool; // version4：指向线程池的指针
};


// namespace TCP_1_3
// {
//     //////////////////////////////////////////////////////////
//     // 业务函数：服务器用于处理业务，可根据需求自定义

//     // 【echo版服务器】：服务端打印从客户端读取到的数据，并将其原封不动返回给客户端
//     static void service(int servicesock, const std::string &clientip, const uint16_t &clientport)
//     {
//         char server_buffer[SIZE];
//         while (true)
//         {
//             // a、读取客户端发来的数据
//             ssize_t s = read(servicesock, server_buffer, sizeof(server_buffer) - 1);
//             if (s > 0)
//             {
//                 server_buffer[s] = '\0'; //\0的ASCII码是0
//                 std::cout << clientip << ":" << clientport << "# " << server_buffer << std::endl;
//             }
//             else if (s == 0)
//             {
//                 logMessage(NORMAL, "read, %s:%d 退出。", clientip.c_str(), clientport);
//                 break;
//             }
//             else
//             {
//                 logMessage(ERROR, "read, 读取失败, %d:%s", errno, strerror(errno));
//                 break;
//             }

//             // b、将读取到的结果返回
//             write(servicesock, server_buffer, strlen(server_buffer));
//         }
//     }

//     // 【version3:多线程版本】：要在新线程中调用server，要将其需要函数参数设置进void*args中。这里使用类来完成。
//     struct threadData
//     {
//         int sock;
//         std::string ip;
//         uint16_t port;
//     };

//     class TcpServer
//     {
//     private:
//         const static int gbacklog = 20; // listen中的参数设置

//         // 【version3:多线程版本】: 为新线程提供的回调函数，设置为静态成员函数是因为非静态成员函数有默认参数this，不符合回调函数的格式要求
//         static void *threadRoutine(void *args)
//         {
//             ////线程分离：结束服务，若不捕捉（捕捉属于阻塞式的，我们要求服务端不能阻塞等待），
//             // 则需要对线程进行分离pthread_detach(pthread_self());以避免系统层面的内存泄漏
//             pthread_detach(pthread_self());
//             threadData *data = static_cast<threadData *>(args); // C++11中的类型转换
//             service(data->sock, data->ip, data->port);
//             // 线程结束时，需要关闭文件描述符、并释放new出来的空间
//             close(data->sock);
//             delete data;
//             return nullptr;
//         }

//     public:
//         TcpServer(uint16_t port, const std::string &ip = "")
//             : _port(port), _ip(ip), _listensock(-1)
//         {
//         }

//         ~TcpServer()
//         {
//             close(_listensock);
//         }

//         // 初始化服务器
//         bool InitServer()
//         {
//             // 1、创建套接字
//             _listensock = socket(AF_INET, SOCK_STREAM, 0); // 这里填入SOCK_STREAM
//             if (_listensock < 0)
//             {
//                 logMessage(ERROR, "socket, 创建套接字失败: %s-%d ", errno, strerror(errno));
//                 exit(2);
//             }
//             logMessage(DEBUG, "socket, 创建套接字成功,sock: %d", _listensock);

//             // 2、绑定
//             struct sockaddr_in localaddr;
//             bzero(&localaddr, 0);
//             localaddr.sin_family = AF_INET;
//             localaddr.sin_addr.s_addr = _ip.empty() ? INADDR_ANY : inet_addr(_ip.c_str()); // 字节序转换
//             localaddr.sin_port = htons(_port);
//             if (bind(_listensock, (struct sockaddr *)&localaddr, sizeof localaddr) < 0)
//             {
//                 logMessage(ERROR, "bind, 绑定失败，%d:%s", errno, strerror(errno));
//                 exit(3);
//             }
//             logMessage(DEBUG, "bind, 绑定成功. ");

//             // 3、监听
//             if (listen(_listensock, gbacklog) < 0)
//             {
//                 logMessage(ERROR, "listen, 监听失败，%d:%s", errno, strerror(errno));
//                 exit(4);
//             }
//             logMessage(DEBUG, "linsten, 监听成功, 初始化套接字完成。");

//             return true;
//         }

//         // 启动服务器
//         void Start()
//         {
//             signal(SIGCHLD, SIG_IGN); // 【version2.1:多进程版本】对SIGCHLD，主动忽略SIGCHLD信号，子进程退出的时候，会自动释放自己的僵尸状态

//             // 网络通讯角度：作为一款网络服务器，永远不退出的！
//             // OS角度：服务器启动-> 进程 -> 常驻进程 -> 永远在内存中存在，除非挂了！
//             while (true)
//             {
//                 // 1、获取连接
//                 // 1.1、准备工作：用于后续从网络中读取客户端的IP、端口号
//                 struct sockaddr_in clientaddr;
//                 memset(&clientaddr, 0, sizeof(clientaddr));
//                 socklen_t len = sizeof(clientaddr);
//                 // 1.2、连接
//                 int servicesock = accept(_listensock, (struct sockaddr *)&clientaddr, &len);
//                 if (servicesock < 0)
//                 {
//                     logMessage(ERROR, "accept, 获取链接失败, servicesock: %d ", servicesock);
//                     continue; // 本次失败了，结束此次循环即可，可下一次重新获取连接
//                 }

//                 // 2、开始进行通讯服务
//                 // 2.1、获取客户端端口号、IP
//                 uint16_t client_port = ntohs(clientaddr.sin_port);      // uint16_t htons(uint16_t hostshort);
//                 std::string client_ip = inet_ntoa(clientaddr.sin_addr); // char *inet_ntoa(struct in_addr in);
//                 logMessage(DEBUG, "accept, 成功获取连接,  servicesock: %d, client: [%s:%d] .", servicesock, client_ip.c_str(), client_port);

//                 ////////////////////////////////////////////////////////////////////////////
//                 // 2.2、根据需求处理客户端数据（服务端的业务处理）

//                 // ——————————【version3:多线程版本】———————————//
//                 // a、准备工作
//                 threadData *td = new threadData; // 在堆上
//                 td->sock = servicesock;
//                 td->ip = client_ip;
//                 td->port = client_port;

//                 pthread_t pid;
//                 // b、创建线程
//                 pthread_create(&pid, nullptr, threadRoutine, (void *)td);

//                 // PS：注意这里不需要close(servicesock);因为主线程和新线程共享资源
//                 //  —————————————————————————————————————————————//

//                 // ——————————【version2.1:多进程版本】———————————//
//                 pid_t pd = fork();
//                 assert(pd != -1);
//                 if (pd == 0) // 子进程
//                 {
//                     close(_listensock); // 子进程：关闭不必要的套接字
//                     if (fork() == 0)    // 在子进程中再fork子进程，得到子子进程（孙子进程）
//                     {
//                         service(servicesock, client_ip, client_port);
//                         exit(0); // 孙子进程，由于子进程关闭，其成为孤儿进程，OS领养， OS在孤儿进程退出的时候，由OS自动回收孤儿进程！
//                     }
//                     exit(0); // 关闭子进程，会导致子子进程变成孤儿进程
//                 }
//                 // 对父进程：
//                 waitpid(pd, nullptr, 0);
//                 close(servicesock); // 父进程：关闭不必要的套接字

//                 // —————————————————————————————————————————————//

//                 // ——————————【version2:多进程版本】———————————//
//                 pid_t pd = fork();
//                 assert(pd >= 0);
//                 if (pd == 0) // 对子进程：处理业务
//                 {
//                     close(_listensock); // 子进程用不到监听套接字，可以关掉（子进程能够继承父进程打开的文件及其fd）
//                     service(servicesock, client_ip, client_port);
//                     exit(0); // 正常退出
//                 }
//                 // 对父进程：继续循环接收客户端的连接请求
//                 close(servicesock); // 父进程用不到accept提供的套接字，可以关掉(对子进程无影响/文件描述符是有限资源，有上限)
//                 // ————————————————————————————————————————————//

//                 // ——————————【version1: 单进程单线程模式】———————————//
//                 service(servicesock, client_ip, client_port);
//                 close(servicesock); // 通讯结束，关闭套接字。
//                 // —————————————————————————————————————————————————//

//                 ////////////////////////////////////////////////////////////////////////////
//             }
//         }

//     private:
//         uint16_t _port;  // 端口号
//         std::string _ip; // IP
//         int _listensock; // 套接字
//     };
// }



#endif